const ts = require('typescript')

/**
 * @type {import('typescript').TransformerFactory<import('typescript').SourceFile>}
 */
module.exports.cypressTransformer = function cypressTransformer(context) {
  /**
   * @type {import('typescript').Visitor}
   */
  const visitor = (node) => {
    if (ts.isSourceFile(node)) {
      return ts.visitEachChild(node, visitor, context)
    }

    const jsDoc = node.jsDoc

    if (jsDoc && Array.isArray(jsDoc)) {
      let cypress
      let declarationName
      jsDoc.forEach((jsDocNode) => {
        try {
          const tags = jsDocNode.tags.filter((tag) => tag.tagName.text === 'cypress')
          if (tags.length) {
            const [tag] = tags
            cypress = tag.comment
          }
          // eslint-disable-next-line no-empty
        } catch {}
      })
      try {
        const [declaration] = node.declarationList.declarations
        if (declaration?.name) {
          declarationName = declaration.name.text
        }
        // eslint-disable-next-line no-empty
      } catch {}
      if (cypress && declarationName) {
        const expression = context.factory.createExpressionStatement(
          context.factory.createBinary(
            context.factory.createPropertyAccess(
              context.factory.createIdentifier(declarationName),
              context.factory.createIdentifier('defaultProps'),
            ),
            ts.SyntaxKind.EqualsToken,
            context.factory.createObjectLiteral([
              context.factory.createSpreadAssignment(
                context.factory.createPropertyAccess(
                  context.factory.createIdentifier(declarationName),
                  context.factory.createIdentifier('defaultProps'),
                ),
              ),
              context.factory.createPropertyAssignment(
                context.factory.createStringLiteral('data-cypress'),
                context.factory.createStringLiteral(cypress),
              ),
            ]),
          ),
        )
        return [node, expression]
      }
      return node
    }
    return ts.visitEachChild(node, visitor, context)
  }

  return (node) => ts.visitNode(node, visitor)
}
